home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
newsgroups
/
misc.20030409-20031118
/
000185_kleine@fh-jena.de_Sun Jun 22 12:57:57 EDT 2003.msg
< prev
next >
Wrap
Text File
|
2020-01-01
|
58KB
|
2,483 lines
Article: 14414 of comp.protocols.kermit.misc
Path: newsmaster.cc.columbia.edu!phl-feed.news.verio.net!nntp1.tagonline.com!nycmny1-snf1.gtei.net!nycmny1-snh1.gtei.net!news.gtei.net!newsfeed!fu-berlin.de!news.uni-leipzig.de!news.uni-jena.de!news.fh-jena.de!not-for-mail
From: Prof Karl Kleine <kleine@fh-jena.de>
Newsgroups: comp.protocols.kermit.misc
Subject: Re: cutape
Date: Sun, 22 Jun 2003 11:32:58 +0000 (UTC)
Organization: Fachhochschule Jena, Germany
Lines: 2461
Sender: Prof Karl Kleine <kleine@hoare.gw.fh-jena.de>
Message-ID: <bd445a$tbh$2@beta.szi.fh-jena.de>
References: <3834495c.0306031601.34eb05ba@posting.google.com> <bbl8ah$pvn$1@watsol.cc.columbia.edu> <3834495c.0306041602.353fa8d6@posting.google.com> <bbnien$ebu$1@watsol.cc.columbia.edu> <3834495c.0306051454.29aa1356@posting.google.com> <bd41r3$tbh$1@beta.szi.fh-jena.de>
NNTP-Posting-Host: hoare.gw.fh-jena.de
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
X-Trace: beta.szi.fh-jena.de 1056281578 30065 194.94.38.12 (22 Jun 2003 11:32:58 GMT)
X-Complaints-To: news@beta.szi.fh-jena.de
NNTP-Posting-Date: Sun, 22 Jun 2003 11:32:58 +0000 (UTC)
User-Agent: tin/1.4.2-20000205 ("Possession") (UNIX) (Linux/2.2.16 (i686))
Xref: newsmaster.cc.columbia.edu comp.protocols.kermit.misc:14414
Prof Karl Kleine <kleine@fh-jena.de> wrote:
> google in usenet groups for my old posting of
> "sltape", which does exactly what you need. It
> reads and writes both ANSI and IBM/MVS tapes
> on Unix systems. Written in C (K&R).
> kl
oops... sltape was the name of the original version.
better look for slt.c, resp. slt-20.c (the version 2)
that I made available. google/usenet has a shar-archive.
but to make it even easier for you, I digged it from my
own archives, and include it at the end of this message.
________________________________________________________
Prof. Karl Kleine http://www.fh-jena.de/~kleine
Fachhochschule Jena kleine@fh-jena.de
Carl-Zeiss-Promenade 2 +49-3641-205-502 [fax -503]
D-07745 Jena, Germany
=============================================================================
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 06/30/1994 19:27 UTC by kleine@bullerbue
# Source directory /usr/fhj/gw/kleine/binsrc
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 6986 -rw-r----- slt-20.1
# 43183 -rw-r----- slt-20.c
#
# ============= slt-20.1 ==============
if test -f 'slt-20.1' -a X"$1" != X"-c"; then
echo 'x - skipping slt-20.1 (File already exists)'
else
echo 'x - extracting slt-20.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'slt-20.1' &&
.\" pltroff -manl $1
.tr ~"
.if t .ds i \(fm\(fm
.if n .ds i ""
.TH SLT 1 FZI-Karlsruhe
.SH NAME
slt \- standard labelled tape processing
.SH SYNOPSIS
.B slt
[
.B -i
]
[
.B -t
tapefile
]
.B -l
.PP
.B slt
[
.B -i
]
[
.B -t
tapefile
]
[
.B -s
]
.B -x
[
file ...
]
.PP
.B slt
[
.B -i
]
[
.B -t
tapefile
]
[
.B -s
]
.B -c
volser owner file/format ...
.SH DESCRIPTION
.I Slt
creates, reads, and lists industry standard \(12" magnetic tapes
according to the
.B "ANSI\|X3.27-1987"
standard entitled
.BR "Magnetic tape labels and file structure for information interchange" .
Internationally, this standard was also adopted by ISO as
.B "ISO\|1001"
and in Germany by DIN as
.BR "DIN\|66029" .
Slt also reads and writes tapes according other editions of these standards.
.PP
If
.I slt
is invoked with a first argument
.BR -i ,
the tape format is IBM/OS standard labelled,
which is similar to the ANSI format, and documented in the IBM manual
.BR "OS\|/\|VS Tape Labels" ,
GC26-3795.
IBM tapes are in the EBCDIC character set.
.PP
.I Slt
is intended for interchange of textual information between
a very wide variety of machines and operating systems,
structured as sequence of lines, generally called records.
In the Unix world a record is a sequence of characters
separated by newline characters.
The characteristics of magnetic tape drives require to put several
records into a larger unit called a block which can be stored on tape.
The relation between blocks and records is called a format, which may be
fixed, where all record have the same length, or variable, where additional
information is stored to describe the length of each record.
.PP
When writing a file onto tape in fixed format, each record is padded
with blanks to the record length, resp. truncated to that length.
Truncations are reported.
Reading a fixed format file reverses that process by removing all trailing
blanks from a line.
.PP
There are three tape processing options:
.TP
.B "-l"
List contents of tape: Label, owner, and then for each file on the tape,
its position, its name, number of blocks, record format,
block and record sizes, creation and expiration dates
is written to standard output.
.TP
.B "-x"
Extract files from tape:
If specified without further parameters, all files are extracted from the tape.
Names are taken from the file header label and translated to lowercase letters.
For non-BSD Unix systems, truncation to 14 characters takes place.
.TP
.BI "-x" "\ \ filename ..."
Extract specific files from tape:
The first file is give the first name provided, the second file the second
name, until the list of names is exhausted.
Files on tape can be skipped by specifying
.I "/dev/null"
or some other junk name as output filename.
.TP
.BI "-c" "\ \ volser\ \ owner\ \ filename/format ..."
Create new tape:
Write a volume label with the volume serial number
.I volser
(max. 6 characters)
and owner name
.I owner
(max. 10 characters).
.I Volser
is also known as "the tape label".
Then append files or change format for files following.
Format and file secifications may freely be mixed.
Unix filenames are stripped of all directory prefixes and are
translated to uppercase.
Wildcarding is supported by shell expansion of filenames prior to execution of
.IR slt .
.PP
Format specifications for newly created tapes:
.TP
.B -ff
Fixed (blocked) format. See above for padding and truncation.
.TP
.B -fd
Variable record format (ANSI).
The record length specifies the maximum size of a line of text.
.TP
.B -fv
Variable record format (IBM).
The
.B -fv
and
.B -fd
formats are synonyms.
.TP
.B -fu
The record format is undefined.
There is no interpretation of the data written to tape; it is just a
byte stream written to tape in blocks of the size specified.
.TP
.BI -b n
The block length is set to
.IR n ,
which must be in the range 18 to 2048 for ANSI tapes.
IBM tapes can have a larger block size.
.TP
.BI -r n
The record length is set to
.IR n .
For fixed (blocked) format, the blocksize must be a multiple
of the record length.
.PP
New settings are reported when the next file is written.
Default format is ANSI standard, blocksize 2048, recordlength 512,
variable record format.
For IBM tapes, the default is blocksize 1600, recordlength 80,
fixed record format.
.PP
An alternate tape drive can be specified by the
.B -t
.I tapefile
option, where
.I tapefile
must be a raw device (character special file) specification for a tape drive,
like
.IR /dev/rmt2 .
.PP
By default,
.I slt
writes a VOL1 header according to the 4th edition (ANSI X3.27-1987) of the
standard. You can also select previous editions by suffixing the
.B -c
option with the edition number, e.g.
.BI -c 3.
.PP
Usually
.I slt
reports what it is doing by messages written to standard output.
You can redirect or
.I tee
this output to a file to get a log what's on the tape,
and send this log with the tape to other sites.
Logging can be suppressed by the silence option
.BR -s .
.PP
Invoking
.I slt
with the help option
.B -h
will print a brief summary of commands.
.PP
When a tape is given to you with the notice that is follows the standard, but
.I slt
does not agree,
the debugging option
.B -D
in front of
.B -l
will log the tape labels.
For interpretation, you should be familiar with the standard definitions.
(If unsuccessful or in doubt, you might also try the
.I analtape
utility by the same author).
.PP
All option flags may also be specified in uppercase.
.SH EXAMPLES
.TP 15
.I "slt\ \ -i\ \ -l"
List all files on an IBM tape.
.TP 15
.I "slt\ \ -x\ \ x\ \ x\ \ x\ \ x\ \ f5\ \ f6"
Skip four files by reading them all into a scratch file
.I x
and then read the 5th and 6th file as files
.I f5
and
.IR f6 .
.TP 15
.I "slt\ \ -c\ \ mytape\ \ whizzard"
Initialize the tape with only a volume label
.I MYTAPE
for owner
.IR WHIZZARD .
Note that these values are always written in uppercase in tape labels.
.TP 15
.I "slt\ \ -c\ \ slt\ \ kleine\ \ slt.c\ \ slt.1"
Create an ANSI tape, labelled
.I SLT
for owner
.I KLEINE
containing two files
.I SLT.C
(the sourcetext of the slt program)
and
.I SLT.1
(the nroff/troff input text for the manual page you are just reading)
in the standard format.
.TP 15
.I "slt\ \ -i\ \ -c\ \ xyz789\ \ poorguy\ \ -ff\ \ -b4000\ \ -r80\ \ punched\ \ cards"
Create an IBM/OS tape for
.I POORGUY
labelled
.I XYZ789
with two files
.I PUNCHED
and
.I CARDS
in 80/4000 fixed blocked format.
.SH FILES
/dev/rmt0
.SH AUTHOR
Karl Kleine, Forschungszentrum Informatik, Karlsruhe, Germany,
(kleine@fzi.de), 1985 to 1992, based on an earlier program
.I sltape
by H. M. Stahl, KUN Nijmegen (NL)
.SH SHORTCOMINGS
.I Slt
does not support multi-volume files, volume sets, spanned records.
Furthermore, only complete tapes can be written;
there is no support for adding files to an existing sequence of files
on a tape.
.I Slt
is intended for interchange of textual information,
and has not been tested on binary information.
The character code translation for ibm tapes may differ from what
siemens or ibm expect.
X
SHAR_EOF
chmod 0640 slt-20.1 ||
echo 'restore of slt-20.1 failed'
Wc_c="`wc -c < 'slt-20.1'`"
test 6986 -eq "$Wc_c" ||
echo 'slt-20.1: original size 6986, current size' "$Wc_c"
fi
# ============= slt-20.c ==============
if test -f 'slt-20.c' -a X"$1" != X"-c"; then
echo 'x - skipping slt-20.c (File already exists)'
else
echo 'x - extracting slt-20.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'slt-20.c' &&
#
/*************************************************************************
**************************************************************************
***
*** s l t standard labelled tape
***
*** according to - ANSI X3.27-1978 (DIN 66029)
*** - IBM OS/VS Tape Labels (IBM Doc GC-26-3795-3)
***
*** written by Karl Kleine, FZI Karlsruhe
*** adapted from 'sltape' by H.M.Stahl,
*** Kath. University of Nijmegen (NL), Informatika
***
*** version march 1992, see program history and PROGID below
***
*** usage
*** listing contents of tape
***
*** slt [ -i ] -l
***
*** creating a new tape (writing disk to tape)
***
*** slt [ -i ] -c volser owner ffs
***
*** where volser is volume serial number (6 chars)
***
*** owner is owner (10 chars)
***
*** ffs is a format / file name sequence
***
*** format consists of three specs:
*** record format (-f), block (-b),
*** and record length (-r) as follows:
***
*** -ff fixed (blocked) format
*** -fv variable format (ibm)
*** -fd variable format (ansi)
*** -fu undefined
*** -bn specifies blocklength,
*** where n is 18 .. 2048
*** -rn specifies record length,
*** where n is a suitable number
***
*** default format is ansi d format with
*** blocksize 2048, recordlength 512.
***
*** file name sequence is a sequence of unix
*** names. if pathnames are specified, directory
*** prefixes are stripped.
***
*** example: slt -i -c slt kleine -ff -b2000 -r80 slt.c
*** this creates a new tape holding one file
*** in ibm/os format, fixed blocked 2000/80.
***
*** the -c option can be followed by a digit 1 to 4,
*** defining the standard version. in essence we follow
*** the common rules, als already defined in version 1
*** of the standard. default is version / level 4 (1987).
*** 4: ANSI X3.27-1987 DIN 66029 Aug 1987
*** 3: ANSI X3.27-1978 DIN 66029 Mai 1979
*** 2: DIN 66029 Jun 1976
*** 1: ANSI X3.27-1969 DIN 66029 Aug 1972
***
*** extracting files from tape
***
*** slt [ -i ] -x file1 file2 ...
***
*** extracts as many files as given from tape
*** and assigns the names specified to them.
***
*** slt [ -i ] -x
***
*** if no names are specified, all files are
*** extracted. attention: the file names on tape
*** are 17 characters long, whereas unix (std)
*** names are are only 14 chars long. this may
*** result in duplicate names and overwriting
*** of files previously extracted. in this case
*** you have to resort to explicit extraction.
***
*** spefication of an alternate tape drive
***
*** slt [ -i ] -t tapedrive ....
***
*** tapedrive must be a raw device which specifies a tape drive,
*** e.g. /dev/rmt2, /dev/rmt0h, whatever it's called in your UNIX
***
*** the -s option switches to silent mode. by default, slt will
*** log on standard output what is is doing in some detail.
***
*** the option -i specifies IBM/OS tape standard to be used in
*** contrast to the default ANSI tape standard. if specified,
*** this option must be given first.
***
*** the debug option -D reports details of tape labels
*** in case of doubt. useful when slt refuses to read a tape
*** which was said to adhere to one of the standards.
***
*** all options are also accepted in upper case.
***
*** volser, owner, and file names are all translated to
*** upper case when writing them to tape. similarly,
*** file names are converted to lower case on extraction.
***
**************************************************************************
*************************************************************************/
X
X
/* revision history:
** V1.0 08-FEB-1985 Karl Kleine, FZI KA
** prototype finished, put into use on
** PCS - F2 of GMDKA at FZI.
** V1.1 31-MAY-1985 blocksize enlarged for ibm tapes,
** minor cleanups
** unix manual page (slt.1) written
** V1.2 10-MAR-1987 sun version / just the program id
** V1.3 28-APR-1989 enlarged temp buf, silly, but shortcut.
** V1.4 26-APR-1990 SunOS 4 version
**
** V2.0 23-MAR-1992 cleanup, removal of old PCS hacks,
** tape selection and proper tape ioctl handling
*/
X
#define PROGID "V2.0 of 23-MAR-1992"
X
/* one of the symbols BSD42, SUNOS3, SUNOS4, ULTRIX4 must be defined.
/* add more machines as needed
*/
X
#define K 1024
X
#ifdef BSD42
#define SYSID "SLT20-BSD42"
#define TAPE "/dev/nrmt0"
#define UBLKS 1024
#define TMPSIZ 32*K
#define SETUP 1
#endif
X
#ifdef SUNOS3
#define SYSID "SLT20-SUNOS3"
#define TAPE "/dev/nrmt0"
#define UBLKS 1024
#define TMPSIZ 32*K
#define SETUP 1
#endif
X
#ifdef SUNOS4
#define SYSID "SLT20-SUNOS4"
#define TAPE "/dev/nrmt0"
#define UBLKS 4*K
#define TMPSIZ 32*K
#include <sys/types.h>
#define SETUP 1
#endif
X
#ifdef ULTRIX4
#define SYSID "SLT20-ULTRIX4"
#define TAPE "/dev/nrmt0h"
#define UBLKS 4*K
#define TMPSIZ 32*K
#define SETUP 1
#endif
X
/* a generic definition, check if this fits you, or make another entry */
X
#ifndef SETUP
#define SYSID "SLT20-UNIX"
#define TAPE "/dev/nrmt0"
#define UBLKS 1024
#define TMPSIZ 32*K
#define SETUP 1
#endif
X
X
/*************************************************************************
*** label field definitions
*************************************************************************/
X
X /* constants for all tape labels */
#define LABLEN 80
#define MAXLABLEN 512
#define LIDPOS 0
#define LIDLEN 4
X /* constants for VOL label */
#define SERPOS 4
#define SERLEN 6
#define VR1POS 10
#define OWNPOS 41
#define OWNLEN 10
#define LSLPOS 79
#define LSLLEN 1
X /* constants for HDR / EOF 1 label */
#define DSNPOS 4
#define DSNLEN 17
#define DSSRPOS 21
#define DSSRLEN 6
#define VSSNPOS 27
#define VSSNLEN 4
#define DSSNPOS 31
#define DSSNLEN 4
#define GENNPOS 35
#define GENNLEN 4
#define GVNPOS 39
#define GVNLEN 2
#define CDPOS 41
#define CDLEN 6
#define EDPOS 47
#define EDLEN 6
#define DSSPOS 53
#define BCPOS 54
#define BCLEN 6
#define SCPOS 60
#define SCLEN 13
X /* constants for HDR / EOF 2 label */
#define RFPOS 4
#define RFLEN 1
#define BLPOS 5
#define BLLEN 5
#define RLPOS 10
#define RLLEN 5
#define TDPOS 15
#define DSPPOS 16
#define JIPOS 17
#define JILEN 17
#define TRTPOS 34
#define TRTLEN 2
#define PCCPOS 36
#define R1POS 37
#define BAPOS 38
#define R2POS 39
#define R2LEN 41
#define BOPOS 50
X
X
/*************************************************************************
*** character translation tables ASCII <--> EBCDIC
*************************************************************************/
X
char etoa[] = /* EBCDIC to ASCII */
{
X 0000,0001,0002,0003,0234,0011,0206,0177,
X 0227,0215,0216,0013,0014,0015,0016,0017,
X 0020,0021,0022,0023,0235,0205,0010,0207,
X 0030,0031,0222,0217,0034,0035,0036,0037,
X 0200,0201,0202,0203,0204,0012,0027,0033,
X 0210,0211,0212,0213,0214,0005,0006,0007,
X 0220,0221,0026,0223,0224,0225,0226,0004,
X 0230,0231,0232,0233,0024,0025,0236,0032,
X 0040,0240,0241,0242,0243,0244,0245,0246,
X 0247,0250,0133,0056,0074,0050,0053,0041,
X 0046,0251,0252,0253,0254,0255,0256,0257,
X 0260,0261,0135,0044,0052,0051,0073,0136,
X 0055,0057,0262,0263,0264,0265,0266,0267,
X 0270,0271,0174,0054,0045,0137,0076,0077,
X 0272,0273,0274,0275,0276,0277,0300,0301,
X 0302,0140,0072,0043,0100,0047,0075,0042,
X 0303,0141,0142,0143,0144,0145,0146,0147,
X 0150,0151,0304,0305,0306,0307,0310,0311,
X 0312,0152,0153,0154,0155,0156,0157,0160,
X 0161,0162,0313,0314,0315,0316,0317,0320,
X 0321,0176,0163,0164,0165,0166,0167,0170,
X 0171,0172,0322,0323,0324,0325,0326,0327,
X 0330,0331,0332,0333,0334,0335,0336,0337,
X 0340,0341,0342,0343,0344,0345,0346,0347,
X 0173,0101,0102,0103,0104,0105,0106,0107,
X 0110,0111,0350,0351,0352,0353,0354,0355,
X 0175,0112,0113,0114,0115,0116,0117,0120,
X 0121,0122,0356,0357,0360,0361,0362,0363,
X 0134,0237,0123,0124,0125,0126,0127,0130,
X 0131,0132,0364,0365,0366,0367,0370,0371,
X 0060,0061,0062,0063,0064,0065,0066,0067,
X 0070,0071,0372,0373,0374,0375,0376,0377,
};
X
char atoe[] = /* ASCII to EBCDIC */
{
X 0000,0001,0002,0003,0067,0055,0056,0057,
X 0026,0005,0045,0013,0014,0015,0016,0017,
X 0020,0021,0022,0023,0074,0075,0062,0046,
X 0030,0031,0077,0047,0034,0035,0036,0037,
X 0100,0117,0177,0173,0133,0154,0120,0175,
X 0115,0135,0134,0116,0153,0140,0113,0141,
X 0360,0361,0362,0363,0364,0365,0366,0367,
X 0370,0371,0172,0136,0114,0176,0156,0157,
X 0174,0301,0302,0303,0304,0305,0306,0307,
X 0310,0311,0321,0322,0323,0324,0325,0326,
X 0327,0330,0331,0342,0343,0344,0345,0346,
X 0347,0350,0351,0112,0340,0132,0137,0155,
X 0171,0201,0202,0203,0204,0205,0206,0207,
X 0210,0211,0221,0222,0223,0224,0225,0226,
X 0227,0230,0231,0242,0243,0244,0245,0246,
X 0247,0250,0251,0300,0152,0320,0241,0007,
X 0040,0041,0042,0043,0044,0025,0006,0027,
X 0050,0051,0052,0053,0054,0011,0012,0033,
X 0060,0061,0032,0063,0064,0065,0066,0010,
X 0070,0071,0072,0073,0004,0024,0076,0341,
X 0101,0102,0103,0104,0105,0106,0107,0110,
X 0111,0121,0122,0123,0124,0125,0126,0127,
X 0130,0131,0142,0143,0144,0145,0146,0147,
X 0150,0151,0160,0161,0162,0163,0164,0165,
X 0166,0167,0170,0200,0212,0213,0214,0215,
X 0216,0217,0220,0232,0233,0234,0235,0236,
X 0237,0240,0252,0253,0254,0255,0256,0257,
X 0260,0261,0262,0263,0264,0265,0266,0267,
X 0270,0271,0272,0273,0274,0275,0276,0277,
X 0312,0313,0314,0315,0316,0317,0332,0333,
X 0334,0335,0336,0337,0352,0353,0354,0355,
X 0356,0357,0372,0373,0374,0375,0376,0377,
};
X
X
/*************************************************************************
*** unix system includes needed
*************************************************************************/
X
#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioccom.h>
#include <sys/mtio.h>
X
X
/*************************************************************************
*** global variables
*************************************************************************/
X
int operation; /* kind of operation wanted */
#define NOOPER 0
#define CREATAPE 1
#define READTAPE 2
#define LISTTAPE 3
X
int standard; /* which standard ? */
#define ANSISTD 0
#define IBMSTD 1
char *stdlevel; /* ANSI std level; default "4" */
X
char *tapename; /* name of tape device */
int tapefid; /* unix file identifier for it */
X
char *volser; /* volume serial number */
char *owner; /* tape owner name */
int fseqno; /* file sequence number on tape */
int recfm; /* record format */
#define FIXED 'f'
#define VAR 'v'
#define AVAR 'd'
#define UNDEF 'u'
int blksize; /* blocksize */
int lrecl; /* record length */
int fchange; /* any of recfm, blksize, lrecl */
X /* changed? needs reporting */
int truncated; /* no of truncated records */
X
X /* extra space at end of buffer */
X /* for NULL chars (printf %s) */
char vollab[LABLEN+2]; /* volume label buffer */
char hdr1lab[LABLEN+2]; /* HDR1 / EOF1 buffer */
char hdr2lab[LABLEN+2]; /* HDR2 / EOF2 buffer */
X
char temp[TMPSIZ]; /* temporary string buffer */
X /* indecently large, should be */
X /* allocated dynamically, but.. */
X
int diskfid; /* unix file identifier for */
X /* disk file to read / write */
X
long clock; /* see time(2), resp. ctime(3) */
int verbose; /* report details flag */
int debug; /* there is always a bug... */
X
X
/*************************************************************************
*** main program
*************************************************************************/
X
main (argc, argv)
X int argc;
X char *argv[];
{
X register int i;
X register int c;
X char *ctime();
X char std;
X
X /* check for legal configuration data first */
X if (sizeof(SYSID) > 13) {
X printf (stderr, "Systemid %s not ANSI X3.27 conformant (>13)\n",
X SYSID);
X exit (-1);
X }
X
X /* identify yourself and tell the time (for a possible log) */
X time (&clock);
X printf ("slt %s / %s run at %s\n", PROGID, SYSID, ctime (&clock));
X
X /* set defaults */
X tapename = TAPE;
X operation = NOOPER; /* none specified yet */
X standard = ANSISTD; /* assume ANSI standard */
X stdlevel = "4";
X fchange = 1; /* set format */
X recfm = AVAR;
X blksize = 2048;
X lrecl = 512;
X verbose = 1; /* report by default */
X fseqno = 0; /* no file touched yet */
X debug = 0;
X
X /* go thru argument list */
X for (i = 1; i < argc; i++)
X {
X if ( (c=argv[i][0]) == '-')
X {
X switch( argv[i][1])
X {
X case 'i': /* -i for IBM tape std */
X case 'I': /* if specified, flag must be first */
X if (i != 1)
X stopit ("-i flag must be first");
X /* set IBM std and associated dflt format */
X standard = IBMSTD;
X recfm = FIXED; /* good old card images */
X blksize = 1600; /* ibm seems to like it */
X lrecl = 80;
X break;
X
X case 'b': /* define blocksize */
X case 'B':
X blksize = atoi (&argv[i][2]);
X fchange++;
X break;
X
X case 'r': /* define record length */
X case 'R':
X lrecl = atoi (&argv[i][2]);
X fchange++;
X break;
X
X case 'f': /* define record format */
X case 'F':
X c = argv[i][2];
X switch (c)
X {
X case 'f':
X case 'F':
X recfm = FIXED;
X break;
X case 'v':
X case 'V':
X case 'd':
X case 'D':
X if (standard == ANSISTD)
X recfm = AVAR;
X else
X recfm = VAR;
X break;
X case 'u':
X case 'U':
X recfm = UNDEF;
X lrecl = blksize;
X break;
X case 's':
X case 'S':
X err ("Spanned records not supported");
X break;
X default:
X err ("Bad format spec");
X }
X fchange++;
X break;
X
X case 'c': /* create a new tape */
X case 'C':
X std = (char)argv[i][2];
X if ('1'<=std && std<='4')
X stdlevel[0] = std;
X if (operation != NOOPER)
X stopit ("Can't redefine operation");
X operation = CREATAPE;
X if (argc-i < 2)
X stopit ("Missing arguments");
X volser = argv[++i];
X owner = argv[++i];
X writevol ();
X break;
X
X case 'x': /* extract files from tape */
X case 'X':
X if (operation != NOOPER)
X stopit ("Can't redefine operation");
X operation = READTAPE;
X readvol1 ();
X if ((i+1) == argc)
X { /* last option, read all files */
X readall ();
X exit (0);
X }
X /* otherwise, read files as names provided */
X break;
X
X case 'l': /* list files on tape */
X case 'L':
X if (operation != NOOPER)
X stopit ("Can't redefine operation");
X operation = LISTTAPE;
X readvol1 ();
X listtape ();
X exit (0);
X
X case 't': /* specify tape drive */
X case 'T': /* must be a raw device file */
X tapename = argv[++i];
X break;
X
X case 's': /* silent mode */
X case 'S':
X verbose = 0;
X break;
X
X case 'D': /* debug flag - see abort handling */
X debug++;
X break;
X
X case 'h':
X case 'H': /* online help */
X helpme ();
X exit (0);
X
X default:
X err ("bad flag - ignored");
X }
X }
X else
X { /* handle file argument */
X if (operation == NOOPER)
X stopit ("No operation [l/c/x] selected");
X else if (operation == CREATAPE)
X writefile (argv[i]);
X else if (operation == READTAPE)
X readfile (argv[i]);
X else
X stopit ("??");
X }
X }
X if (operation == CREATAPE)
X {
X tapewtm ();
X tapewtm ();
X taperew ();
X }
X else if (operation == NOOPER)
X {
X helpme ();
X }
}
X
X
numopt (cp)
X char *cp;
{
X if (cp == 0)
X return (0);
X else
X return (atoi(cp));
}
X
X
helpme ()
{
X printf ("\nANSI or IBM/OS standard labelled tape processing:\n\n");
X printf (" slt -l list contents of tape\n");
X printf (" slt -x a b c extract 3 files as a, b, c\n");
X printf (" slt -x extract all files\n");
X printf (" slt -c volser owner a b c create new tape\n");
X printf (" slt -t rawdev [-l|-c|-x]... use tape drive rawdev\n\n");
X printf (" specifying -i as first flag selects IBM OS/VS format\n\n");
X printf ("read manual page for advanced usage!\n");
}
X
X
/***********************************************************************
*** listing file properties
***********************************************************************/
X
listtape ()
{
X printf (
"\nseq# filename creat expir blocks f blks lrecl created by\n");
X printf (
X "----------------------------------------------------------------------\n");
X for (;;)
X {
X /* read hdr labels -- will finish on EOT */
X readhdr (1);
X if (debug)
X printf ("\n--- reading HDR1/2:\n%80s\n%80s\n",
X hdr1lab, hdr2lab);
X /* skip data blocks -- to next tape mark */
X tapefsf ();
X if (debug)
X printf ("--- forward skip file\n");
X /* read eof labels and report */
X readhdr (0);
X if (debug)
X printf ("--- reading EOF1/2:\n%80s\n%80s\n\n",
X hdr1lab, hdr2lab);
X listfile ();
X }
}
X
X
listfile ()
{
X /* data set seq number and data set name (filename) */
X lstlab (hdr1lab, DSSNPOS, DSSNLEN, " ");
X lstlab (hdr1lab, DSNPOS, DSNLEN, " ");
X
X /* creation and expiration date (leading blank part of field) */
X lstlab (hdr1lab, CDPOS, CDLEN, "");
X lstlab (hdr1lab, EDPOS, EDLEN, " ");
X
X /* number of blocks */
X lstlab (hdr1lab, BCPOS, BCLEN, " ");
X
X /* format, blocksize, record length */
X lstlab (hdr2lab, RFPOS, RFLEN, " ");
X lstlab (hdr2lab, BLPOS, BLLEN, " ");
X lstlab (hdr2lab, RLPOS, RLLEN, " ");
X
X /* created by */
X lstlab (hdr1lab, SCPOS, SCLEN, "\n");
}
X
X
/*************************************************************************
*** reading and writing of files
*************************************************************************/
X
readfile (ufn)
X char *ufn;
{
X int format, bcount;
X char *unixfn;
X char *getlfnlc(), *getlfnuc();
X
X /* next file header labels -- will finish on EOT */
X readhdr (1);
X
X /* select tape format */
X recfm = getlrecfm();
X
X if (standard == ANSISTD)
X { /* encode both format and direction of transfer */
X if (recfm == 'F')
X format = 'f';
X else if (recfm == 'D')
X format = 'd';
X else
X format = 'u';
X } else
X {
X if (recfm == 'V')
X format = 'v';
X else format = 'a';
X }
X
X fseqno++;
X if (verbose)
X printf ("%d. %s ==> ", fseqno, getlfnuc());
X
X if (ufn == 0)
X /* use name on tape */
X unixfn = getlfnlc ();
X else
X /* use name provided */
X unixfn = ufn;
X
X if (verbose)
X printf ("%s", unixfn);
X
X if ((diskfid = creat (unixfn, 0644)) < 0)
X ioabort ("Can't create Unix file\n");
X
X blksize = getlblks();
X blksize += (blksize % 2); /* must be even - stupid controller */
X
X bcount = movefil (tapefid, diskfid, blksize, UBLKS,
X getllrecl(), format, 0);
X
X if (verbose)
X printf (" (%d tape blocks)\n", bcount);
X
X close(diskfid);
X
X /* read and forget eof labels */
X readhdr (0);
X return (1);
}
X
X
readall ()
{
X printf ("Extracting all files on tape...\n");
X for (;;)
X readfile ((char *)0);
}
X
X
writefile (ufn)
X char *ufn;
{
X int format, bsi;
X int bcount;
X char *unixname;
X char *leafname(), *getlfnuc();
X
X if (standard == ANSISTD)
X { /* encode both format and direction of transfer */
X if (recfm == FIXED)
X format = 'F';
X else if (recfm == VAR)
X {
X recfm = AVAR;
X format = 'D';
X }
X else if (recfm == AVAR)
X format = 'D';
X else format = 0;
X }
X else if (recfm == VAR)
X format = 'V';
X else format = 'E';
X
X if (fchange)
X {
X fchange = 0;
X if (verbose)
X tellform ();
X if (!formatok ())
X {
X printf ("file %s ignored\n\n", ufn);
X return;
X }
X }
X
X /* strip directories from unix pathname */
X unixname = leafname (ufn);
X
X if ((diskfid = open (ufn, 0)) < 0)
X {
X fprintf (stderr, "Can't open file \"%s\" -- ignored\n", ufn);
X return;
X }
X
X /* write header labels */
X fseqno++;
X mkhdr1 (unixname, fseqno, 0, 1);
X mkhdr2 (1);
X if (verbose)
X printf ("%d. %s ==> %s ", fseqno, ufn, getlfnuc());
X writehdrs ();
X
X /* set input blocksize */
X if ((standard == ANSISTD) && ((blksize % 512) == 0))
X bsi = blksize;
X else bsi = UBLKS;
X
X /* write data blocks */
X truncated = 0;
X bcount = movefil (diskfid, tapefid, bsi, blksize, lrecl, format, 0);
X tapewtm ();
X
X close (diskfid);
X
X if (bcount == -1)
X {
X tapewtm ();
X taperew ();
X exit (-1);
X }
X else
X {
X /* write eof labels */
X mkhdr1 (unixname, fseqno, bcount, 0);
X mkhdr2 (0);
X writehdrs ();
X
X if (debug)
X { printf (" written to\n");
X listfile ();
X printf ("\n");
X }
X else if (verbose)
X printf (" (%d tape blocks)\n", bcount);
X
X if (truncated)
X {
X printf ("**** %d truncated input records", truncated);
X if (verbose || debug)
X printf ("\n");
X else
X printf (" for file %s\n", ufn);
X }
X
X return(1);
X }
}
X
X
formatok ()
{
X if (recfm == FIXED)
X {
X if ( lrecl > 0 && blksize % lrecl)
X stopit ("Blocksize must be multiple of record length");
X }
X if (recfm == VAR)
X {
X if (standard == ANSISTD)
X {
X if (blksize < 18)
X {
X err ("Blocksize must at least be 18 bytes");
X blksize = 18;
X return (0);
X }
X if (blksize > 2048)
X err ("Blocksize should be upto 2048 bytes");
X }
X if ((blksize - lrecl) < 4)
X stopit (
"Blocksize must be at least 4 bytes greater than record length");
X if (lrecl < 5)
X stopit ("Record length too small for recfm=V");
X }
X return(1);
}
X
X
tellform ()
{
X printf ("\nBlock size %d, record length %d, record format %c\n",
X blksize, lrecl, (recfm & 0337));
}
X
X
char *
leafname (path)
X char *path;
{
X register char *p, *q;
X
X p = q = path;
X while (*p != '\0')
X if (*p++ == '/')
X q = p;
X return (q);
}
X
X
/*************************************************************************
*** reading / writing tape labels
*************************************************************************/
X
readvol1 ()
{
X char *getlvser(), *getlown();
X
X tapeopen ();
X if (!readlab (vollab))
X ioabort ("Reading volume label");
X if (isvol ())
X {
X printf ("Volume serial number \"%s\", ", getlvser ());
X printf ("tape owner \"%s\", ", getlown());
X liststd ();
X } else {
X if (debug)
X printf ("Bad volume label <%s>\n", vollab);
X stopit ("Bad VOL1 label\n");
X }
}
X
X
liststd ()
{
X char *getlstd();
X
X if (standard == ANSISTD)
X printf ("ANSI X3.27 level %s label.\n", getlstd());
X else
X printf ("IBM std label.\n");
}
X
X
readhdr (hdrflag)
X int hdrflag;
{
X if (!readlab (hdr1lab) || !readlab (hdr2lab))
X {
X printf ("EOT\n"); /* eof == end of tape reached */
X exit (0);
X }
X tapefsf (); /* skip user labels and tape mark */
X if (hdrflag) /* header ? */
X {
X if (ishdr (hdr1lab) && ishdr (hdr2lab))
X return;
X if (debug)
X {
X printf ("Bad file header label(s):\n");
X printf ("*** HDR1 ***\n%80s\n", hdr1lab);
X printf ("*** HDR2 ***\n%80s\n", hdr2lab);
X }
X stopit ("Missing or badly formed header label");
X }
X else
X {
X if (iseof (hdr1lab) && iseof (hdr2lab))
X return;
X if (debug)
X {
X printf ("Bad end of file label(s):\n");
X printf ("*** EOF1 ***\n%80s\n", hdr1lab);
X printf ("*** EOF2 ***\n%80s\n", hdr2lab);
X }
X stopit ("Missing or badly formed eof label");
X }
}
X
X
writevol ()
{
X tapecreat ();
X upcase (volser);
X upcase (owner);
X mkvol1 ();
X writelab (vollab);
X printf ("Volume initialized, volser \"%s\", owner \"%s\", ",
X volser, owner);
X liststd ();
}
X
X
writehdrs ()
{
X writelab (hdr1lab);
X writelab (hdr2lab);
X tapewtm ();
}
X
X
/*************************************************************************
*** label composition
*************************************************************************/
X
mkvol1 ()
{
X clearlab (vollab, 0, LABLEN);
X
X /* label identifier */
X putlab (vollab, LIDPOS, LIDLEN, "VOL1");
X
X /* reserved field */
X if (standard == IBMSTD)
X putlab (vollab, VR1POS, 1, "0");
X
X /* volume serial number */
X putlab (vollab, SERPOS, SERLEN, volser);
X
X /* owner of tape */
X putlab (vollab, OWNPOS, OWNLEN, owner);
X
X /* label standard level */
X if (standard == ANSISTD)
X putlab (vollab, LSLPOS, 1, stdlevel);
}
X
X
mkhdr1 (name, number, bcount, hdr)
X char name[]; /* data det name */
X int number; /* data set sequence number on tape */
X int bcount; /* block count */
X int hdr; /* flag: 1 for HDR1, 0 for EOF1 */
{
X struct tm *convtime; /* converted time; see upm, ctime(3) */
X int year, day;
X
X clearlab (hdr1lab, 0, LABLEN);
X
X /* label identifier */
X if (hdr)
X putlab (hdr1lab, LIDPOS, LIDLEN, "HDR1");
X else
X putlab (hdr1lab, LIDPOS, LIDLEN, "EOF1");
X
X /* data set identifier */
X putlab (hdr1lab, DSNPOS, DSNLEN, name);
X
X /* data set serial number */
X putlab (hdr1lab, DSSRPOS, DSSRLEN, volser);
X
X /* volume sequence number */
X putlab (hdr1lab, VSSNPOS, VSSNLEN, "0001");
X
X /* data set sequence number */
X putlabint (hdr1lab, DSSNPOS, DSSNLEN, number);
X
X /* generation number */
X putlab (hdr1lab, GENNPOS, GENNLEN, "0001");
X
X /* version number of generation */
X putlab (hdr1lab, GVNPOS, GVNLEN, "00");
X
X /* creation date, julian date form (year, day in year) */
X convtime = gmtime (&clock);
X year = convtime->tm_year;
X day = convtime->tm_yday;
X putlabint (hdr1lab, CDPOS+1, 2, year);
X putlabint (hdr1lab, CDPOS+3, 3, day);
X
X /* expiration date */
X putlabint (hdr1lab, EDPOS+1, 2, year);
X putlabint (hdr1lab, EDPOS+3, 3, day);
X
X /* data set security */
X putlab (hdr1lab, DSSPOS, 1," ");
X
X /* block count */
X if (hdr)
X putlabint (hdr1lab, BCPOS, BCLEN, 0);
X else
X putlabint (hdr1lab, BCPOS, BCLEN, bcount);
X
X /* system code */
X putlab (hdr1lab, SCPOS, SCLEN, SYSID);
}
X
X
mkhdr2 (hdr)
X int hdr; /* header flag, see mkhdr1 */
{
X clearlab (hdr2lab, 0, LABLEN);
X
X /* label identifier */
X if (hdr)
X putlab (hdr2lab, LIDPOS, LIDLEN, "HDR2");
X else
X putlab (hdr2lab, LIDPOS, LIDLEN, "EOF2");
X
X /* record format */
X if (recfm == FIXED)
X putlab (hdr2lab, RFPOS, 1, "F");
X else if (recfm == AVAR)
X putlab (hdr2lab, RFPOS, 1, "D");
X else if (recfm == VAR)
X putlab (hdr2lab, RFPOS, 1, "V");
X else
X putlab (hdr2lab, RFPOS, 1, "U");
X
X /* block length */
X putlabint (hdr2lab, BLPOS, BLLEN, blksize);
X
X /* record length */
X putlabint (hdr2lab, RLPOS, RLLEN, lrecl);
X
X if (standard == IBMSTD)
X {
X /* tape density == 1600 bpi */
X putlab (hdr2lab, TDPOS, 1, "3");
X
X /* data set position */
X putlab (hdr2lab, DSPPOS, 1, "0");
X
X /* job/step identification */
X putlab (hdr2lab, JIPOS, JILEN, "STDTAPE /SLT");
X
X /* tape recording technique */
X putlab (hdr2lab, TRTPOS, TRTLEN, " ");
X
X /* printer control characters */
X putlab (hdr2lab, PCCPOS, 1, " ");
X
X /* reserved 1 -- must be blank*/
X putlab (hdr2lab, R1POS, 1, " ");
X
X /* block attributes */
X if (blksize != lrecl)
X putlab (hdr2lab, BAPOS, 1, "B");
X }
X else if (standard == ANSISTD)
X {
X /* buffer offset */
X putlab (hdr2lab, BOPOS, 2, "00");
X }
}
X
X
/*************************************************************************
*** label field access
*************************************************************************/
X
clearlab (label, start, leng)
X char label[];
X int start, leng;
{
X register int i;
X for (i = start; i < start+leng; i++)
X label[i] = ' ';
}
X
X
putlab (label, pos, maxlen, string)
X char label[];
X int pos, maxlen;
X char string[];
{
X register int i;
X register char c;
X for (i = 0; i < maxlen && (c = *string++) != '\0'; i++)
X {
X if ( c >= 'a' && c <= 'z') /* label in uppercase */
X c &= ~040;
X label[pos+i] = c;
X }
}
X
X
putlabint (label, pos, len, num)
X char *label;
X int pos, len, num;
{
X /* put integer with length 'len' to 'pos' in 'label'
X * insert leading zeros where needed */
X int i, rest;
X
X rest = num;
X for (i=len+pos-1; i >= pos; i --)
X {
X label[i] = (rest % 10) + '0';
X rest = rest / 10;
X }
}
X
X
lstlab (label, pos, length, trailer)
X char *label, *trailer;
X int pos, length;
{
X char *p;
X
X p = &label[pos];
X while (length--)
X putchar (*p++);
X printf ("%s", trailer);
}
X
X
char *
getlab (label, pos, length, lowcase)
X char *label;
X int pos, length, lowcase;
{
X register int i;
X register char c;
X
X for ( i=0; i < length && (c = label[pos + i]) != ' '; i++)
X {
X if (lowcase && c >= 'A' && c <= 'Z')
X temp[i] = c + 'a' - 'A';
X else
X temp[i] = c;
X }
X temp[i] = '\0';
X return (temp);
}
X
X
getlabint (label, pos, len)
X char *label;
X int pos, len;
{
X /* read an integer from a label */
X register int i, num;
X
X num = 0;
X for (i = 0; i < len; i++)
X num = num * 10 + label[pos+i] - '0';
X return (num);
}
X
X
getlabchar (label, pos)
X char *label;
X int pos;
{
X return (label[pos]);
}
X
X
/*************************************************************************
*** specific label field access routines
*************************************************************************/
X
char *
getlvser ()
{
X return (getlab (vollab, SERPOS, SERLEN, 0));
}
X
char *
getlown ()
{
X return (getlab (vollab, OWNPOS, OWNLEN, 0));
}
X
char *
getlstd ()
{
X return (getlab (vollab, LSLPOS, LSLLEN, 0));
}
X
char *
getlfnuc ()
{
X return (getlab (hdr1lab, DSNPOS, DSNLEN, 0));
}
X
char *
getlfnlc ()
{
X return (getlab (hdr1lab, DSNPOS, DSNLEN, 1));
}
X
getlblks ()
{
X return (getlabint (hdr2lab, BLPOS, BLLEN));
}
X
getllrecl ()
{
X return (getlabint (hdr2lab, RLPOS, RLLEN));
}
X
getlrecfm ()
{
X return (getlabchar (hdr2lab, RFPOS) & 0337);
}
X
getldssn ()
{
X return (getlabint (hdr1lab, DSSNPOS, DSSNLEN));
}
X
X
/*************************************************************************
*** reading / writing tape labels
*************************************************************************/
X
readlab (lab)
X char *lab;
{
X int r;
X char *strncpy ();
X r= read (tapefid, temp, MAXLABLEN);
X if (r >= LABLEN)
X {
X strncpy (lab, temp, LABLEN);
X if (standard == IBMSTD)
X toascii (lab, LABLEN);
X return (1);
X }
X else if (r < 0)
X { /* error */
X ioabort ("Can't read tape label");
X /* never come here, but please lint */
X return (0);
X }
X else return (0);
}
X
writelab (lab)
X char *lab;
{
X int w;
X
X if (standard == IBMSTD)
X toebcdic (lab, LABLEN);
X
X w = write (tapefid, lab, LABLEN);
X if (w < 0)
X ioabort ("Can't write tape label");
}
X
X
/*************************************************************************
*** label type checking
*************************************************************************/
X
isvol ()
{
X return (cmpstr ("VOL1", getlab (vollab, LIDPOS, LIDLEN, 0)) == 0);
}
X
ishdr (lab)
X char *lab;
{
X return (cmpstr ("HDR", getlab (lab, LIDPOS, 3, 0)) == 0);
}
X
iseof (lab)
X char *lab;
{
X if (cmpstr ("EOF", getlab (lab, LIDPOS, 3, 0)) == 0)
X return (1);
X if (cmpstr ("EOV", getlab (lab, LIDPOS, 3, 0)) == 0)
X return (1);
X else return (0);
}
X
X
/*************************************************************************
*** moving the data -- the actual work
*************************************************************************/
X
#define LCASE 01
#define UCASE 02
#define PAD 020 /* pad input records to ibs */
X
int cflag;
int fflag;
int ibf; /* input file descriptor */
int obf; /* output file descriptor */
int ibs; /* input buffer size */
int obs; /* output buffer size */
int cbs; /* conversion buffer size */
char *ibuf; /* input buffer */
char *obuf; /* output buffer */
char *rbuf;
int ibc; /* input block count (number of chars read) */
int obc; /* output block count (number of chars written) */
int cbc;
int lr;
int nifr; /* number of filled input blocks */
int nipr; /* number of partially filled input blocks */
int nofr; /* number of filled output blocks */
int nopr; /* number of partially filled output blocks */
char *op;
char *rp; /* pointer into record buffer (for var recs) */
int nspace;
X
char *sbrk(); /* sbrk() returns ptr to buffer */
X
X
movefil (infile, outfile, pibs, pobs, pcbs, code, cas)
X int infile, outfile; /* filedescriptors */
X int pibs, pobs, pcbs; /* block sizes */
X int code, cas; /* translations */
{
X register (*conv)();
X register char *ip;
X register c;
X int fixibm(), unfixibm(), null (), cnull();
X int fix(), unfix();
X int var(), unvar();
X int varibm(), unvaribm();
X int a;
X
X /* globalize parms -- artefact of old pgm */
X ibf = infile;
X obf = outfile;
X ibs = pibs;
X obs = pobs;
X cbs = pcbs;
X conv = null;
X fflag = 0;
X cflag = 0;
X
X nipr = 0; nifr = 0; nopr = 0; nofr = 0; nspace = 0;
X
X /* translations */
X switch (code)
X {
X case 'E': conv = fixibm; break; /* to tape */
X case 'a': conv = unfixibm; break; /* from tape */
X case 'F': conv = fix; break; /* to tape */
X case 'f': conv = unfix; break; /* from tape */
X case 'V': conv = varibm; break; /* to tape */
X case 'v': conv = unvaribm; break; /* from tape */
X case 'D': conv = var; break; /* to tape */
X case 'd': conv = unvar; break; /* from tape */
X }
X if (cas == 'l')
X cflag |= LCASE;
X if (cas == 'u')
X cflag |= UCASE;
X
X if (conv == null && cflag&(LCASE|UCASE))
X conv = cnull;
X if (ibs == 0)
X ibs = UBLKS;
X if (obs == 0)
X obs = UBLKS;
X if (ibs == obs && conv == null)
X fflag ++;
X
X /* get buffers */
X ibuf = sbrk (ibs);
X if (fflag)
X {
X obuf = ibuf;
X rbuf = ibuf;
X }
X else
X {
X obuf = sbrk (obs);
X if (code == 'D' || code == 'V' )
X rbuf = sbrk (cbs);
X else rbuf=obuf;
X }
X if ((ibuf == (caddr_t) -1)
X || (obuf == (caddr_t) -1)
X || (rbuf == (caddr_t) -1))
X stopit ("Insufficient memory for buffers");
X ibc = 0;
X obc = 0;
X cbc = 0;
X lr = 0;
X op = obuf;
X
X if (conv == varibm)
X {
X /* reserve block length field */
X op += 4;
X obc = 4;
X /* reserve record length field */
X rp = rbuf + 4;
X cbc = 4;
X }
X if (conv == var )
X {
X /* reserve record length field */
X rp = rbuf + 4;
X cbc = 4;
X }
X rp = rbuf+4;
X
X
X /* now do the job */
loop:
X if (ibc-- == 0)
X {
X /* read a block */
X ibc = read (ibf, ibuf, ibs);
X if (ibc == -1) /* read error */
X {
X perror ("read");
X flsh ();
X exit (-1);
X }
X if (ibc == 0) /* eof */
X {
X if (conv == var)
X { /* pad buffer with '^' */
X a = obs - obc;
X while ( a--)
X null ('^');
X }
X if (conv == varibm)
X {
X /* insert block length */
X putlength (obuf,obc);
X
X a = obs - obc;
X while (a--)
X null (0);
X }
X flsh ();
X brk (ibuf);
X return (nopr+nofr);
X }
X if (ibc != ibs) /* partial block read */
X {
X nipr++;
X if ( cflag & PAD )
X {
X /* pad input buffer to ibs with 0's */
X for (ip = &ibuf[ibs]; ip > &ibuf[ibc]; )
X *--ip = '\0';
X ibc = ibs;
X }
X } else
X nifr++;
X
X ip = ibuf;
X if (conv == unvaribm)
X {
X /* get block length from input block ;
X ** must built ibc explicitly in two assignments,
X ** otherwise there might be reordering of
X ** expression by c compiler (lint saw it...) */
X ibc = ((*ip++) << 8 );
X ibc |= ((*ip++) & 0377) ;
X ip++; ip++;
X ibc -= 4; /* account for length field */
X }
X ip = ibuf;
X if (conv == unvaribm)
X ip = ip + 4;
X
X /* no conversions to be done ? */
X if (fflag)
X {
X obc = ibc;
X flsh ();
X ibc = 0;
X }
X goto loop;
X }
X c = 0;
X c |= *ip++;
X (*conv)(c);
X goto loop;
}
X
flsh ()
{
X if (obc)
X {
X if (obc == obs)
X nofr++;
X else
X {
X nopr++;
X if (obc & 01 && obf == tapefid)
X {
X /* prevent writing out uneven number of bytes
X tapeunit does not like it */
X *op = 0;
X obc ++ ;
X }
X }
X if (write (obf, obuf, obc) != obc)
X ioabort ("write");
X obc = 0;
X }
}
X
X
cnull (cc)
{
X register c;
X
X c = cc;
X if (cflag&UCASE && c>='a' && c<='z')
X c += 'A'-'a';
X if (cflag&LCASE && c>='A' && c<='Z')
X c += 'a'-'A';
X null (c);
}
X
null (c)
{
X *op = c;
X op++;
X if (++obc >= obs)
X {
X flsh ();
X op = obuf;
X }
}
X
X
/* unfixibm - convert fixed format records from tape to
** unix format and translate them to ascii
** throw away trailing blanks
** insert newline character at end of line
*/
X
unfixibm (cc)
{
X register c;
X
X c = 0;
X c |= etoa[cc & 0377];
X if (cbs == 0)
X {
X cnull (c);
X return;
X }
X if (c == ' ')
X nspace++;
X else
X {
X while (nspace > 0)
X {
X null (' ');
X nspace--;
X }
X cnull (c);
X }
X if (++cbc >= cbs)
X {
X null ('\n');
X cbc = 0;
X nspace = 0;
X }
}
X
X
/* unfix - convert fixed record format records from tape
** to unix format (no code conversion)
** throw away trailing blanks
** insert newline character at end of record
*/
X
unfix (cc)
{
X register c;
X
X c = cc;
X if (cbs == 0)
X {
X cnull (c);
X return;
X }
X if (c == ' ')
X nspace++;
X else
X {
X while (nspace > 0)
X {
X null (' ');
X nspace--;
X }
X cnull (c);
X }
X if (++cbc >= cbs)
X {
X null ('\n');
X cbc = 0;
X nspace = 0;
X }
}
X
X
/* fixibm - convert unix files to fixed record fromat records
** for tape, translate to ebcdic
** newlines are discarded
** records are padded with spaces to the desired record length
*/
X
fixibm (cc)
{
X register c;
X
X c = cc;
X if (cflag&UCASE && c>='a' && c<='z')
X c += 'A'-'a';
X if (cflag&LCASE && c>='A' && c<='Z')
X c += 'a'-'A';
X c = atoe[c] & 0377;
X if (cbs == 0)
X {
X null (c);
X return;
X }
X /* translate tabs to blanks */
X if (cc == '\t')
X {
X c = atoe[' '];
X while ((cbc < cbs) && ( cbc+1 & 07 ))
X {
X null (c);
X cbc ++;
X }
X }
X else if (cc == '\n')
X {
X c = atoe[' '];
X while (cbc < cbs)
X {
X null (c);
X cbc++;
X }
X cbc = 0;
X return;
X }
X if (cbc == cbs)
X truncated++;
X cbc++;
X if (cbc <= cbs)
X null (c);
}
X
X
/* fix - convert unix files to fixed record format records for
** tape, no character translation
** newlines are discarded
** records are padded with spaces up to the desired recordlength
*/
X
fix (cc)
{
X register c;
X
X c = cc;
X if (cbs == 0)
X {
X cnull (c);
X return;
X }
X if (cc == '\n')
X {
X while (cbc < cbs)
X {
X null (' ');
X cbc++;
X }
X cbc = 0;
X return;
X }
X if (cbc == cbs)
X truncated++;
X cbc++;
X if (cbc <= cbs)
X cnull (c);
}
X
X
/* convert unix disk file to ANSI variable blocked format D
** files on tape.
** newlines (\n) are discarded, i.e. taken as end-of-record indicators.
** records do not span blocks
** blocks not completely filled are padded with ANSI padding char '^'
** to full output block size.
*/
X
var (cc)
X int cc;
{
X register c, l;
X register char *lrp;
X int i;
X c = cc;
X if (cc == '\n')
X { /* end of input record reached */
X l = (cbc > cbs ? cbs : cbc );
X
X /* insert ANSI format record length field */
X lrp = rbuf+4;
X for ( i=4; i > 0; i-- )
X {
X *--lrp = (l % 10) + '0';
X l = l / 10;
X }
X
X copyr: /* copy record to output buffer */
X lrp = rbuf;
X l = (cbc > cbs ? cbs : cbc );
X if ( obc + l <= obs)
X { /* record fits in block */
X while (l--)
X cnull (*lrp++);
X cbc = 4;
X rp = rbuf+4;
X return;
X }
X else
X { /* pad the block, make new block */
X l = obs - obc;
X while (l--)
X cnull ('^');
X goto copyr;
X }
X }
X if (cbc == cbs ) /* truncated record */
X truncated ++;
X cbc++;
X if (cbc <= cbs )
X *rp++ = c; /* char to record */
}
X
X
/* convert ANSI blocked variable format D records files on tape
** to unix file on disk.
** a newline (\n) will be append after every record on disk.
*/
X
unvar (cc)
X int cc;
{
X register c;
X c = cc;
X if (cbc < 4)
X { /* still in length field */
X if (c == '^')
X return;
X lr = lr * 10 + c - '0';
X cbc ++;
X if (cbc == 4 && lr == 4)
X { /* empty record */
X cbc = 0;
X lr = 0;
X null ('\n');
X }
X return;
X }
X cnull (c);
X cbc ++;
X if (cbc == lr)
X { /* at end of record */
X cnull ('\n');
X lr = 0;
X cbc = 0;
X }
}
X
X
/* convert IBM blocked variable format V record files
** to unix files on disk.
** translate from ebcdic to ascii.
** append newline (\n) to every record on disk.
*/
X
unvaribm (cc)
{
X register c;
X c = cc;
X if (cbc < 4)
X { /* still in record length field */
X if (cbc == 0)
X lr = c;
X else if (cbc == 1)
X lr = (lr << 8) + (c & 0377) ;
X cbc ++;
X if (cbc == 4 && lr == 4)
X { /* empty record - shouldn't happen on ibm */
X cbc = 0;
X lr = 0;
X null ('\n');
X }
X return;
X }
X cnull (etoa[c & 0377]);
X cbc ++;
X if (cbc == lr)
X { /* at end of record */
X null ('\n');
X lr = 0;
X cbc = 0;
X }
}
X
X
/* convert unix files on disk to IBM blocked variable format V
** record files on tape.
** translate from ascii to ebcdic.
** records do not span blocks.
** blocks not completely filled are padded to output blocksize
** with null characters (the block length field however contains
** the block length without padding chars).
*/
X
varibm (cc)
{
X register c, l;
X register char *lrp;
X
X c = cc;
X if (c == '\n')
X { /* end of input record */
X l = (cbc > cbs ? cbs : cbc );
X /* insert record length */
X putlength (rbuf,l);
X
X copyrec: /* copy record to output buffer */
X lrp = rbuf;
X if (obc + l <= obs)
X { /* record fits in block */
X if (obc + l == obs)
X { /* record first exactly */
X /* insert block length */
X putlength (obuf,obs);
X while (l--)
X null (*lrp++);
X obc = 4;
X op += 4;
X cbc = 4;
X rp = rbuf+4;
X return;
X }
X while (l--)
X null (*lrp++);
X cbc = 4;
X rp = rbuf+4;
X return;
X }
X else
X { /* complete block and write it */
X /* insert block length */
X putlength (obuf,obc);
X
X /* pad with zero chars to obs */
X l = obs - obc;
X while (l-- )
X null (0);
X op = op + 4;
X obc = 4;
X
X /* block written, write record to next */
X l = (cbc > cbs ? cbs : cbc );
X goto copyrec;
X }
X }
X if (cflag&UCASE && c>='a' && c<='z')
X c += 'A'-'a';
X else if (cflag&LCASE && c>='A' && c<='Z')
X c += 'a'-'A';
X c = atoe[c] & 0377;
X
X if (cbc == cbs)
X truncated++ ; /* record truncated */
X cbc++;
X if (cbc <= cbs)
X *rp++ = c; /* char to record buffer */
}
X
X
/* insert length to block or record.
** IBM length field: byte 1 and 2 contain the length, byte 3 and 4 zero.
** (don't forget: IBM count the bytes from left to right).
*/
X
putlength (buf,len)
X char *buf;
X int len;
{
X register char *p;
X
X p = buf + 4;
X *--p = 0; *--p = 0; /* two zero bytes */
X *--p = len & 0377;
X *--p = len >> 8; /* halfword with binary length */
}
X
X
/* buffer translation routines
** ebcdic to ascii and asci to ebcdic
*/
X
toascii (buf,len)
X char *buf;
X int len;
{
X register char *ip;
X register c;
X for (ip = buf; ip < buf+len; )
X {
X c = etoa[*ip &0377];
X *ip++ = c;
X }
}
X
toebcdic (buf,len)
X char *buf;
X int len;
{
X register char *ip;
X register c;
X for (ip = buf; ip < buf+len; )
X {
X c = *ip;
X *ip++ = atoe[c & 0377];
X }
}
X
X
/*************************************************************************
*** tape command emulation
*************************************************************************/
X
X
struct mtget mtg;
struct mtop mto;
X
X
tapeopen ()
{
X if ((tapefid = open (tapename, 0)) < 0)
X ioabort ("Cant open tape file\n");
X mustbetape ();
X taperew ();
}
X
X
tapecreat ()
{
X if ((tapefid = creat (tapename, 0)) < 0)
X ioabort ("Can't open tape file for writing / ring?\n");
X mustbetape ();
X taperew ();
}
X
mustbetape ()
{
X if (ioctl (tapefid, MTIOCGET, &mtg) < 0) {
X if (errno == ENOTTY) {
X fprintf (stderr, "SLT: %s is not a tape device\n",
X tapename);
X exit (-1);
X } else {
X ioabort ("error getting tape status");
X }
X }
}
X
tapewtm ()
{
X if (debug)
X printf ("\n---------------- TAPEMARK\n");
X mto.mt_op = MTWEOF;
X mto.mt_count = 1;
X if (ioctl (tapefid, MTIOCTOP, &mto) < 0)
X perror ("tape/wtm");
}
X
X
tapefsf ()
{
X mto.mt_op = MTFSF;
X mto.mt_count = 1;
X if (ioctl (tapefid, MTIOCTOP, &mto) < 0)
X perror ("tape/fsf");
}
X
X
taperew ()
{
X mto.mt_op = MTREW;
X mto.mt_count = 1;
X ioctl (tapefid, MTIOCTOP, &mto);
X /* ignore errors on rewind, as taperew may be called in closed
X ** file state, after some error had occurred, just to be safe */
}
X
X
/*************************************************************************
*** writing messages, error reports
*************************************************************************/
X
ioabort (msgtext)
X char *msgtext;
{
X perror (msgtext);
X taperew ();
X exit (-1);
}
X
X
stopit (msgtext)
X char *msgtext;
{
X fprintf( stderr, "\nABORT: %s\n", msgtext);
X if (debug)
X abort (); /* trap for debugger if any,
X ** write 'core' file */
X else
X taperew ();
X exit (-1);
}
X
X
err (msgtext)
X char *msgtext;
{
X fprintf (stderr, "\nERROR: %s\n", msgtext);
}
X
X
cmpstr (s1,s2)
X char *s1, *s2;
{
X register char *p1, *p2;
X char c1, c2;
X
X p1 = s1;
X p2 = s2;
X while ( (c1 = *p1++) == ( c2 = *p2++))
X if (c1 == '\0')
X return(0);
X return (c2 - c1);
}
X
X
upcase (s)
X char *s;
{
X register char *p;
X register char c;
X p = s;
X while (c = *p)
X if ('a' <= c && c <= 'z')
X *p++ = c + 'A'-'a';
X else
X p++;
}
X
X
/*************************************************************************
*** end of program 'slt'
*************************************************************************/
SHAR_EOF
chmod 0640 slt-20.c ||
echo 'restore of slt-20.c failed'
Wc_c="`wc -c < 'slt-20.c'`"
test 43183 -eq "$Wc_c" ||
echo 'slt-20.c: original size 43183, current size' "$Wc_c"
fi
exit 0